package br.com.caelum.missao.dao;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import br.com.caelum.missao.ConnectionFactory;
import br.com.caelum.missao.modelo.Missao;

@Repository
public class JdbcMissaoDao {
	private final Connection connection;
	@Autowired
	public JdbcMissaoDao(DataSource datasource) {
		try {
			this.connection = new ConnectionFactory().getConnection();
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}

	public void adiciona(Missao missao) {
		String sql = "insert into missao (descricao, finalizado) values (?,?)";
		PreparedStatement stmt;
		try {
			stmt = connection.prepareStatement(sql);
			stmt.setString(1, missao.getDescricao());
			stmt.setBoolean(2, missao.isFinalizado());
			stmt.execute();
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}

	public void remove(Long id) {

		if (id == null) {
			throw new IllegalStateException("Id da missao não deve ser nula.");
		}

		String sql = "delete from missao where id = ?";
		PreparedStatement stmt;
		try {
			stmt = connection.prepareStatement(sql);
			stmt.setLong(1, id);
			stmt.execute();
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}

	public void altera(Missao missao) {
		String sql = "update missao set descricao = ?, finalizado = ?, dataFinalizacao = ? where id = ?";
		PreparedStatement stmt;
		try {
			stmt = connection.prepareStatement(sql);
			stmt.setString(1, missao.getDescricao());
			stmt.setBoolean(2, missao.isFinalizado());
			stmt.setDate(3, missao.getDataFinalizacao() != null ? new Date(
					missao.getDataFinalizacao().getTimeInMillis()) : null);
			stmt.setLong(4, missao.getId());
			stmt.execute();
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}

	public List<Missao> lista() {
		try {
			List<Missao> missao = new ArrayList<Missao>();
			PreparedStatement stmt = this.connection
					.prepareStatement("select * from missao");

			ResultSet rs = stmt.executeQuery();

			while (rs.next()) {
				// adiciona a missao na lista
				missao.add(populaMissao(rs));
			}

			rs.close();
			stmt.close();

			return missao;
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}

	public Missao buscaPorId(Long id) {

		if (id == null) {
			throw new IllegalStateException("Id da missao não deve ser nula.");
		}

		try {
			PreparedStatement stmt = this.connection
					.prepareStatement("select * from missao where id = ?");
			stmt.setLong(1, id);

			ResultSet rs = stmt.executeQuery();

			if (rs.next()) {
				return populaMissao(rs);
			}

			rs.close();
			stmt.close();

			return null;
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}

	public void finaliza(Long id) {

		if (id == null) {
			throw new IllegalStateException("Id da missao não deve ser nula.");
		}

		String sql = "update missao set finalizado = ?, dataFinalizacao = ? where id = ?";
		PreparedStatement stmt;
		try {
			stmt = connection.prepareStatement(sql);
			stmt.setBoolean(1, true);
			stmt.setDate(2, new Date(Calendar.getInstance().getTimeInMillis()));
			stmt.setLong(3, id);
			stmt.execute();
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}

	private Missao populaMissao(ResultSet rs) throws SQLException {
		Missao missao = new Missao();

		// popula o objeto missao
		missao.setId(rs.getLong("id"));
		missao.setDescricao(rs.getString("descricao"));
		missao.setFinalizado(rs.getBoolean("finalizado"));

		// popula a data de finalizacao da missao, fazendo a conversao
		Date data = rs.getDate("dataFinalizacao");
		if (data != null) {
			Calendar dataFinalizacao = Calendar.getInstance();
			dataFinalizacao.setTime(data);
			missao.setDataFinalizacao(dataFinalizacao);
		}
		return missao;
	}
}
